Skip to content

fix: address ten reproducible issues from September triage - #1218

Merged
1jehuang merged 1788 commits into
masterfrom
fix/issue-triage-20260910-pr
Sep 19, 2026
Merged

1jehuang merged 1788 commits into
masterfrom
fix/issue-triage-20260910-pr

Conversation

@1jehuang

@1jehuang 1jehuang commented Sep 10, 2026 •

Copy link
Copy Markdown
Owner

Summary

Ten scoped fixes from the newest-50 issue triage, with one issue-referencing commit each. Six are new fixes from this pass and four were already present in the local branch base and have been revalidated and explicitly published here. No contributor branch was imported. Unrelated local telemetry, embedding, provider, and workflow changes are excluded.

Issue Change Observed focused verification
#1184 Do not rearm terminal focus reporting from focus events 4 TUI focus tests passed
#1186 Refresh local-client global skills before initial History, after the SSH early return 17 skill and 47 SSH tests passed, with overlap. Corrected negative control fails without the fix
#1187 Reap notification children without blocking the caller 4 process tests passed across both crates. 2 subprocess entry points are intentionally ignored by the outer runner
#1188 Preserve explicit sponsor opt-outs across save/load 8 sponsor configuration tests passed
#1189 Create promoted background output artifact before returning 20 background tests and 1 real Bash timeout-promotion test passed. Running output may still be empty, this is not live streaming
#1194 Allow scheduled NotifySession through subscription-free dispatch to the existing handler 5 runner, 2 busy/idle notification, and 80 protocol tests passed. Real isolated socket regression failed before the fix and passed six post-fix executions
#1201 Acquire environment lock before rendering lock in both affected tests 3 source-order regressions and both actual TUI tests passed. Original sites rejected by negative control
#1204 Preserve Cargo caller working directory outside the Jcode checkout 3 baseline failures became 5 passing real Cargo workspace tests. Existing job-sizing tests and shell syntax passed
#1206 Normalize completed non-image file drops, not partial key streams 7 targeted tests, 26 drop-filter tests and 15 input tests passed, with overlap. Initial 4 failures became green
#1214 Preserve arbitrary MCP arguments in provider-facing schemas 14 MCP tests passed, including schema dialect and strict-mode regressions

Review and validation limits

  • CI follow-through (September 10): the published head has an actual failed CI workflow-validation run, not merely pending tests. GitHub reports (Line: 16, Col: 1): env is already defined. The Windows smoke and iOS workflow also failed before jobs. These failures are absent from the PR check rollup, where only Require Linked Issue passes. Draft status is not the cause, and marking ready would not repair invalid YAML. The separate CI broken since Aug 20: duplicate top-level env in ci.yml, ios-testflight.yml, windows-smoke.yml (Invalid workflow file) #1191 / fix: safe fixes from September 7 issue triage #1193 workflow repair remains the prerequisite. No branch was imported and no CI failure was bypassed.

  • Draft, not merge-ready. This does not bypass failed or pending required checks. Existing draft fix: safe fixes from September 7 issue triage #1193 owns the separate CI broken since Aug 20: duplicate top-level env in ci.yml, ios-testflight.yml, windows-smoke.yml (Invalid workflow file) #1191 workflow/formatting repair. Its last checked result is 8 passed and 3 failed: Quality Guardrails, Ubuntu Build & Test, and macOS Build & Test. Those changes are not duplicated here. Resolve that baseline CI work and run this branch's full checks before merging.

  • Exact published snapshot now verified: archived head 0e84b661a1c437b2376398a9be4409b5def6664b was compiled independently through the host-wide Cargo gate. All 17 focused Rust cohorts listed above passed on the resulting executables, as did all five Cargo workspace tests, job-sizing tests, shell syntax and three source-order regressions. All 1,886 tracked archive files were checked against their published Git blob hashes after testing. This supersedes the initial working-branch-only validation limitation. It is not a full workspace CI run.

  • selfdev test and the coordinated TUI build were blocked before compilation by a pre-existing missing telemetry Git blob. The repository's host-wide Cargo gate was used for local fallback. Remote build host was unavailable, and early high-memory compiler attempts were terminated by earlyoom. Successful focused reruns are the evidence above, not those failed attempts.

  • The first CLI build timed out at ten minutes. A warmed continuation then completed in 2m59s. The exact CLI and a real isolated TUI/daemon both reported v0.84.0-dev (0e84b661a). The acceptance checks below used that binary with private home/runtime/socket and no inherited API credentials. No shared daemon was reloaded or stopped.

  • Full workspace CI, live Kimi decoding, native macOS/Windows runtime and real SSH host validation remain unverified. The real isolated TUI reached provider selection and reported every provider as not configured. Therefore no live-provider scheduler response is claimed. The scheduler regression uses real sockets with a fake provider, and notification lifecycle tests use instrumented notifier processes. These are narrower evidence, not replacements for the unavailable native/provider acceptance paths.

  • No issue has been closed and no PR has been merged or released by this triage pass.

Observed public-interface behavior

Whole-result rerun after requirement mapping

Re-executed all 17 mapped Rust cohorts, five real Cargo workspace tests, job-sizing/shell checks and three lock-order checks against the complete published head. All passed again, and all 1,886 tracked source hashes still matched afterward. The 28-row requirement ledger records each observed output and its evidence boundary, including the still-failing baseline CI prerequisite rather than calling it passed.

Repeated the actual native TUI skill/frame, escaped-path/transcript/read, preference persistence, Bash/background lifecycle and deferred MCP stdio workflows successfully. Repeated native Ghostty focus checks observed actual focus events followed by 0.00% Jcode CPU, 0.40% Ghostty CPU and zero new draw samples over five seconds. Repeated real desktop notification delivery returned from the public API in 7,764µs and reaped the real child before parent exit. Private windows/processes were cleaned up. Test-driver corrections for onboarding dismissal and the correct TOML field were made before the successful complete rerun, without production edits.

Fresh GitHub reads over all 50 initially selected issues reconfirmed one bucket each, 30 newly owner-answered issues, 23 newly labeled issues, all 33 signed comments and ten fix links. All issues remain open. Native Windows/macOS, real SSH and live-provider/Kimi checks remain unverified, and full CI is still blocked. This rerun does not make the PR merge-ready.

Fixes #1184
Fixes #1186
Fixes #1187
Fixes #1188
Fixes #1189
Fixes #1194
Fixes #1201
Fixes #1204
Fixes #1206
Fixes #1214


— Jcode agent (automated triage), on behalf of @1jehuang

1jehuang and others added 30 commits August 24, 2026 18:44
…ilent

When browser setup had already completed but Firefox was simply not
running, the bridge stopped responding and every message pointed the
agent at action='setup', which is a one-time install/repair flow. Agents
then re-ran setup (reopening the extension installer) instead of just
starting Firefox.

- Detect whether Firefox is running (per-OS) and, when the bridge is
  installed but silent because Firefox is closed, launch Firefox
  detached and wait for the bridge to reconnect before failing.
- ensure_firefox_ready() now auto-launches Firefox and proceeds with the
  requested action when the bridge reconnects, prefixing a note.
- browser setup and 'jcode browser status'/tool status now distinguish
  'Firefox is not running' from a genuinely broken install and say setup
  is one-time and not needed again.
- JCODE_BROWSER_AUTOLAUNCH=0 disables the auto-launch (also used to keep
  tests hermetic).
@1jehuang

Copy link
Copy Markdown
Owner Author

Scoped review complete. Integrating the ten contribution commits as ancestry-preserving 16b6badd0, not the unrelated old branch diff. Conflict resolution retains the newer tmux extended-key lifecycle tests and existing MCP collision/identity policy.

Exact combined executable 7d25a5646 passed real isolated TUI/daemon checks: skill Tab completion before History, three focus cycles without focus-report rearming, escaped file-drop submission and actual file read, bracketed paste, account preference writes preserving sponsor opt-out, and foreground Bash timeout promotion with readable empty output while Running and final output after completion.

Fresh named regressions also pass for notification child reaping/missing executable (both paths), real subscribed-client scheduled delivery, idle/busy NotifySession, dynamic MCP schemas/strict-mode exclusion, five real Cargo-cwd cases, all seven file-drop cases, local/SSH skill isolation, tmux terminal recovery, and both actual lock-sensitive tests plus lock-order negative controls. These are Linux/local-fixture checks, not native Ghostty/macOS/Windows or live Kimi acceptance. Full hosted CI has unrelated baseline formatting failures documented in #1193.

@1jehuang
1jehuang merged commit 16b6bad into master Sep 19, 2026
9 checks passed
@greptile-apps

greptile-apps Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 3/5

Not safe to merge until the invalid workflow definitions and background-output failure are fixed. The notification reaper and typed-path behavior should also be addressed, but do not independently block merging.

Findings

  1. P1 Reject unavailable output storage ▶
  2. P2 Bound notification reapers ▶
  3. P2 Preserve typed path syntax ▶
Fix with agent prompt
### Issue 1
crates/jcode-base/src/background.rs:654-658
When the configured output directory cannot create the initial artifact, this discarded write error still allows `adopt_with_options` to publish and return a running task. Callers are then directed to retrieve output but receive `None`, so background work appears usable while its output is unavailable. Fail adoption before publishing the task, or explicitly expose the initialization failure.

### Issue 2
crates/jcode-app-core/src/notifications.rs:563-568
Each notification starts a detached OS thread that blocks in `child.wait()` until its notifier exits. Repeated notifications with slow or hung notifier processes retain one additional thread each, which can exhaust process resources. This is a non-blocking hardening concern; use bounded child supervision or enforce notifier termination.

### Issue 3
crates/jcode-tui/src/tui/app/input.rs:2916-2919
Submitting ordinary keyboard input parses every complete existing local path as a dropped path before preserving the prompt. A typed quoted or shell-escaped filename is sent without its quotes or escapes, changing the text the user entered. This is a non-blocking input-integrity concern; only normalize input with explicit drop or paste provenance.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

This change introduces two merge-blocking failures: both GitHub Actions workflow files contain duplicate top-level environment mappings, and adopted background tasks can be returned without an available output artifact. It also introduces two non-blocking concerns: notification child reaping can accumulate waiting threads, and typed quoted or escaped file paths are altered on submission.

Reviews (1) · Last reviewed commit: "fix: load local client skills before ini..."

Comment on lines +654 to +658
// Retain an output artifact before publishing the running task or
// returning its ID. Adopted work buffers its output until completion,
// when the wrapper below replaces this initially empty file. Create it
// before spawning that wrapper so a fast completion cannot be truncated.
let _ = std::fs::write(&output_path, "");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Reject unavailable output storage

When the configured output directory cannot create the initial artifact, this discarded write error still allows adopt_with_options to publish and return a running task. Callers are then directed to retrieve output but receive None, so background work appears usable while its output is unavailable. Fail adoption before publishing the task, or explicitly expose the initialization failure.

Artifacts

Evidence from the check

  • This authored test holds an adopted task running and compares a writable output root with a file used as an invalid output root, exercising `adopt_with_options` and `output`; it demonstrates the caller-visible missing-output condition.

Evidence from the check

  • This authored script builds the isolated Rust test manifest and captures both control and invalid-output-root executions with command, working directory, and exit code; it provides repeatable proof.

Command output from the check

  • The executed writable-directory control run exited 0 and shows the returned output file exists while running and `manager_output_while_running=Some("")`; the expected output contract holds.

Command output from the check

  • The executed invalid-root run exited 0 and shows `adopt_with_options` returned a task while `output_file_exists_while_running=false` and `manager_output_while_running=None`; the defect is confirmed.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/jcode-base/src/background.rs
Line: 654-658

Comment:
**Reject unavailable output storage**

When the configured output directory cannot create the initial artifact, this discarded write error still allows `adopt_with_options` to publish and return a running task. Callers are then directed to retrieve output but receive `None`, so background work appears usable while its output is unavailable. Fail adoption before publishing the task, or explicitly expose the initialization failure.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +563 to +568
fn reap_notification_child(mut child: std::process::Child) {
let _ = std::thread::Builder::new()
.name("jcode-notification-child".to_string())
.spawn(move || {
let _ = child.wait();
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Bound notification reapers

Each notification starts a detached OS thread that blocks in child.wait() until its notifier exits. Repeated notifications with slow or hung notifier processes retain one additional thread each, which can exhaust process resources. This is a non-blocking hardening concern; use bounded child supervision or enforce notifier termination.

Artifacts

Evidence from the check

  • The authored Rust harness preserves the production reaper body, starts controllably long-lived children, and asserts kernel thread growth; it directly tests the reported mechanism.

Command output from the check

  • The recorded rustc command built the focused harness successfully, establishing that the executable test was ready to run.

Command output from the check

  • The zero-call baseline executed successfully and recorded one process thread with zero growth, providing the comparison condition.

Command output from the check

  • The 64-call reproduction executed successfully and recorded 64 started waiters and 64 additional Linux process threads while the children remained alive, confirming unbounded one-per-child growth.

Command output from the check

  • The captured source excerpt shows the blocking detached reaper at lines 563-568 and its Linux `notify-send` call path, confirming applicability on the validated platform.

Command output from the check

  • The recorded diff check completed successfully after artifact creation, confirming no whitespace errors were introduced.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/jcode-app-core/src/notifications.rs
Line: 563-568

Comment:
**Bound notification reapers**

Each notification starts a detached OS thread that blocks in `child.wait()` until its notifier exits. Repeated notifications with slow or hung notifier processes retain one additional thread each, which can exhaust process resources. This is a non-blocking hardening concern; use bounded child supervision or enforce notifier termination.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines 2916 to +2919
pub(super) fn take_prepared_input(app: &mut App) -> PreparedInput {
promote_dropped_images(app);
let raw_input = std::mem::take(&mut app.input);
app.record_prompt_history(&raw_input);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Preserve typed path syntax

Submitting ordinary keyboard input parses every complete existing local path as a dropped path before preserving the prompt. A typed quoted or shell-escaped filename is sent without its quotes or escapes, changing the text the user entered. This is a non-blocking input-integrity concern; only normalize input with explicit drop or paste provenance.

Artifacts

Evidence from the check

  • Temporary test source copied before cleanup; it types both path forms character-by-character and calls `take_prepared_input`, showing the exact behavior exercised.

Command output from the check

  • Captured command output for the focused Rust test; both typed forms become the unquoted and unescaped path, confirming normalization is not limited to paste/drop events.

Command output from the check

  • Captured cleanup command output showing the temporary test changes were reverted from the product source tree.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/jcode-tui/src/tui/app/input.rs
Line: 2916-2919

Comment:
**Preserve typed path syntax**

Submitting ordinary keyboard input parses every complete existing local path as a dropped path before preserving the prompt. A typed quoted or shell-escaped filename is sent without its quotes or escapes, changing the text the user entered. This is a non-blocking input-integrity concern; only normalize input with explicit drop or paste provenance.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@greptile-apps

greptile-apps Bot commented Sep 19, 2026

Copy link
Copy Markdown

Comments Outside Diff

These findings sit on lines the diff does not cover, so they could not be posted inline. Each one leaves this list once its file changes.

  • P1 Merge environment mappings .github/workflows/ci.yml:18 ▶

    This workflow defines the top-level env key twice. GitHub Actions rejects duplicate YAML mapping keys before jobs run, so CI cannot execute. Merge JCODE_CI into the existing environment mapping; .github/workflows/ios-testflight.yml has the same defect.

  • P1 Duplicate top-level env keys invalidate both GitHub Actions workflows ▶

    • Bug
      • .github/workflows/ci.yml defines env at lines 3-4 and again at lines 16-18. .github/workflows/ios-testflight.yml defines env at lines 3-4 and again at lines 18-21. The executed strict duplicate-key parse rejects both documents, so GitHub Actions workflow validation will reject them rather than execute them.
    • Cause
      • Each YAML mapping may only define a given key once, but both root mappings define env twice.
    • Fix
      • Merge each workflow's two root-level env blocks into one root-level env mapping, retaining JCODE_CI: "1" together with the variables currently in the later block.
  • P1 Adopted task is published despite failed output-file initialization ▶

    • Bug
      • When the configured background output root cannot contain files, adopt_with_options still returns a task ID and registers the task. While it remains running, callers receive None from output(task_id) instead of the promised empty output artifact.
    • Cause
      • The initial std::fs::write(&output_path, "") at crates/jcode-base/src/background.rs:658 discards its error (let _ = ...) and the method has no fallible return path or pre-publication failure handling.
    • Fix
      • Make adoption fail before publishing/registering when output-file creation fails (for example, return Result<BackgroundTaskInfo> and propagate contextual I/O errors), or otherwise explicitly represent and surface output initialization failure rather than returning a normal task.
  • P2 Notification child reaper creates one unbounded blocking OS thread per live child ▶

    • Bug
      • Each successful notification process spawn passes its child to reap_notification_child, which creates a detached named OS thread that blocks in child.wait(). The executable harness reproduced 64 concurrent live children producing 64 additional process threads (1 to 65). Repeated notifications whose notifier children do not exit therefore accumulate OS threads without a bound until those children terminate.
    • Cause
      • reap_notification_child uses std::thread::Builder::spawn once per child and performs a synchronous blocking Child::wait inside each detached thread. There is no concurrency limit, queue, timeout, or shared reaping mechanism.
    • Fix
      • Use bounded child supervision instead of a new blocking OS thread per notification (for example, a bounded worker/reaper queue), or ensure notifier invocation has an enforced timeout/termination policy. Preserve child reaping while limiting the number of concurrently blocked waiters.
  • P2 Typed existing paths are normalized as dropped paths at submission ▶

    • Bug
      • A normal key-by-key typed existing local path enclosed in quotes or using shell escapes is parsed as a dropped path when take_prepared_input calls promote_dropped_images. The submitted raw_input and expanded message lose those quotes and escapes.
    • Cause
      • take_prepared_input unconditionally invokes promote_dropped_images before taking app.input and recording history. promote_dropped_images accepts any parse_dropped_paths match, while parse_dropped_paths accepts existing quoted and escaped local filesystem paths without tracking whether they came from a terminal drop/paste event.
    • Fix
      • If typed shell syntax must be preserved, gate path promotion on explicit drop/paste provenance rather than only on parse_dropped_paths; otherwise document that complete existing typed paths are intentionally normalized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment